package com.mxpio.erp.technology.controller;

import com.alibaba.excel.EasyExcel;
import com.mxpio.erp.common.enums.OrderStatusEnums;
import com.mxpio.erp.common.technology.entity.BomInfo;
import com.mxpio.erp.common.technology.entity.BomInfoLine;
import com.mxpio.erp.common.technology.service.BomInfoLineService;
import com.mxpio.erp.common.technology.service.BomInfoService;
import com.mxpio.erp.common.technology.service.EasyexcelUploadForTechService;
import com.mxpio.erp.common.technology.service.VBomInfoService;
import com.mxpio.erp.common.technology.vo.*;
import com.mxpioframework.common.vo.Result;
import com.mxpioframework.filestorage.entity.MxpioFileInfo;
import com.mxpioframework.filestorage.service.FileStorageService;
import com.mxpioframework.jpa.policy.CrudContext;
import com.mxpioframework.jpa.policy.impl.SmartCrudPolicyAdapter;
import com.mxpioframework.jpa.query.Criteria;
import com.mxpioframework.jpa.query.Operator;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Tag(name = "BomInfoController", description = "Bom接口")
@RestController
@RequestMapping("/erp/tech/bom/")
public class BomInfoController {

    @Autowired
    private BomInfoService bomInfoService;

    @Autowired
    private BomInfoLineService bomInfoLineService;
    @Autowired
    private EasyexcelUploadForTechService uploadForTechService;

    @Resource(name = FileStorageService.BEAN_ID)
    private FileStorageService fileService;
    @Autowired
    private VBomInfoService vBomInfoService;

    @PostMapping("listByItem/{itemCode}")
    @Operation(summary = "Bom列表", description = "获取Bom列表（无分页）", method = "POST")
    public Result<BomInfo> listByItem(@Parameter(description="父物料编号") @PathVariable(name = "itemCode", required = true) String itemCode,
                                            @Parameter(description="版本号") @RequestBody VersionVO vo ){
        BomInfo bomInfo = bomInfoService.listBom(itemCode,vo,false);
        return Result.OK(bomInfo);
    }

    @GetMapping("history/{itemCode}")
    @Operation(summary = "Bom历史列表", description = "获取Bom历史列表（无分页）", method = "GET")
    public Result<List<BomInfo>> history(@Parameter(description="父物料编号") @PathVariable(name = "itemCode", required = true) String itemCode){
        List<BomInfo> bomInfos = bomInfoService.listHistory(itemCode);
        return Result.OK(bomInfos);
    }

    @PostMapping("listSub")
    @Operation(summary = "查询Bom子级", description = "查询Bom子级", method = "POST")
    public Result<List<BomInfoLine>> listSub(@RequestBody BomTreeVO vo){
        List<BomInfoLine> bomInfoLines = bomInfoService.listSub(vo);
        return Result.OK(bomInfoLines);
    }

    @GetMapping("list")
    @Operation(summary = "Bom列表", description = "获取Bom列表（无分页）", method = "GET")
    public Result<List<BomInfo>> list(Criteria criteria) throws UnsupportedEncodingException {
        List<BomInfo> bomInfos = bomInfoService.list(BomInfo.class,criteria);
        return Result.OK(bomInfos);
    }
    @GetMapping("page")
    @Operation(summary = "Bom分页，以物料为基础展示", description = "获取Bom列表（分页）", method = "GET")
    public Result<Page<BomInfo>> page(Criteria criteria, Integer pageSize, Integer pageNo) throws UnsupportedEncodingException {
        Pageable page = PageRequest.of(pageNo-1, pageSize);
        return Result.OK(bomInfoService.page(page,criteria));
    }


    @GetMapping("list/{bomId}")
    @Operation(summary = "根据bomId获取Bom", description = "根据bomId获取Bom", method = "GET")
    public Result<BomInfo> getById(@PathVariable(name = "bomId", required = true) String bomId) {
        BomInfo bomInfo = bomInfoService.getById(BomInfo.class, bomId);
        return Result.OK(bomInfo);
    }

    @RequestMapping("save")
    @Operation(summary = "保存Bom", description = "保存Bom")
    public Result<BomInfo> save(@RequestBody BomInfo bomInfo) {
        bomInfoService.save(bomInfo,new SmartCrudPolicyAdapter(){
            @Override
            public boolean beforeInsert(CrudContext context) {
                Object o = context.getEntity();
                if(o instanceof BomInfoLine){
                    ((BomInfoLine) o).setBomId(bomInfo.getBomId());
                }
                return true;
            }
        });
        return Result.OK(bomInfo);
    }

    @DeleteMapping("remove/{bomIds}")
    @Operation(summary = "根据bomIds删除Bom", description = "删除Bom", method = "DELETE")
    @Transactional(readOnly = false)
    public Result<BomInfo> remove(@Parameter(description="bomId，多个id用英文逗号分隔") @PathVariable(name = "bomIds", required = true) String bomIds) {
        String[] bomId = bomIds.split(",");
        for(String key : bomId){
            Criteria c = Criteria.create().addCriterion("bomId", Operator.EQ, key);
            bomInfoLineService.removeBatch(BomInfoLine.class, c);
            bomInfoService.delete(BomInfo.class, key);
        }
        return Result.OK();
    }

    @PutMapping("submit/{bomId}")
    @Operation(summary = "提交Bom", description = "提交Bom", method = "PUT")
    public Result<BomInfo> submit(@Parameter(description="bomId") @PathVariable(name = "bomId", required = true) String bomId) {
        BomInfo bomInfo = bomInfoService.getById(BomInfo.class,bomId);
        if(bomInfo.getUseType().equals(OrderStatusEnums.BomStatus.CREATE.getStatusCode())){
            return bomInfoService.updateBomStatus(bomInfo, OrderStatusEnums.BomStatus.AUDITING);
        }else {
            return Result.error("非新增状态不可提交");
        }
    }

    @PutMapping("audit/{bomId}")
    @Operation(summary = "审核Bom", description = "审核Bom", method = "PUT")
    public Result<BomInfo> audit(@Parameter(description="bomId") @PathVariable(name = "bomId", required = true) String bomId) {
        BomInfo bomInfo = bomInfoService.getById(BomInfo.class,bomId);
        if(bomInfo.getUseType().equals(OrderStatusEnums.BomStatus.AUDITING.getStatusCode())){
            return bomInfoService.updateBomStatus(bomInfo, OrderStatusEnums.BomStatus.USING);
        }else {
            return Result.error("非审核中状态不可审核");
        }
    }

    @PutMapping("abandon/{bomId}")
    @Operation(summary = "弃审Bom", description = "弃审Bom", method = "PUT")
    public Result<BomInfo> abandon(@Parameter(description="bomId") @PathVariable(name = "bomId", required = true) String bomId) {
        BomInfo bomInfo = bomInfoService.getById(BomInfo.class,bomId);
        if(bomInfo.getUseType().equals(OrderStatusEnums.BomStatus.AUDITING.getStatusCode())){
            return bomInfoService.updateBomStatus(bomInfo, OrderStatusEnums.BomStatus.CREATE);
        }else{
            return Result.error("非审核中状态不可审核");
        }
    }

    @PutMapping("expired/{bomId}")
    @Operation(summary = "失效Bom", description = "失效Bom", method = "PUT")
    public Result<BomInfo> expired(@Parameter(description="bomId") @PathVariable(name = "bomId", required = true) String bomId) {
        BomInfo bomInfo = bomInfoService.getById(BomInfo.class,bomId);
        return bomInfoService.updateBomStatus(bomInfo, OrderStatusEnums.BomStatus.EXPIRED);
    }
    @PutMapping("voided/{bomId}")
    @Operation(summary = "作废Bom", description = "作废Bom", method = "PUT")
    public Result<BomInfo> voided(@Parameter(description="bomId") @PathVariable(name = "bomId", required = true) String bomId) {
        BomInfo bomInfo = bomInfoService.getById(BomInfo.class,bomId);
        return bomInfoService.updateBomStatus(bomInfo, OrderStatusEnums.BomStatus.CREATE);
    }

    @PostMapping("consumption")
    @Operation(summary = "材料定额领取计算", description = "材料定额领取计算", method = "POST")
    public Result<String> consumption(@RequestBody ConsumptionVO vo) {
        ImmutablePair<String,String> pair = bomInfoService.consumption(vo);
        if(StringUtils.isBlank(pair.getRight())){
            return Result.OK(pair.getLeft());
        }
        return Result.error(pair.getRight());
    }

    @GetMapping("calcAll")
    @Operation(summary = "计算所有bomline的消耗量，需要进行计算的bomline消耗量初始化为小于0", description = "计算所有bomline的消耗量", method = "GET")
    public Result<List<BomInfoLine>> calcAll() {
        bomInfoService.clacAll();
        return Result.OK();
    }


    @PostMapping("upload")
    @Operation(summary = "BOM直接生效数据模板导入", description = "BOM直接生效数据模板导入")
    public Result<?> uploadBom(HttpServletRequest request) {
        try{
            MultipartHttpServletRequest multipartRequest =null;
            if (request instanceof MultipartHttpServletRequest) {
                multipartRequest = (MultipartHttpServletRequest)(request);
            }else {
                return Result.error("请在请求头中设置key:Content-Type,value:multipart/form-data");
            }
            MultipartFile file = multipartRequest.getFile("file");// 获取上传文件对象
            List<BomInfoImportModel> readModelList =  uploadForTechService.uploadBom(file.getInputStream());
            int yesSize = 0;
            int successSize = 0;
            int errorSize = 0;
            //StringBuffer sb = new StringBuffer("失败原因：");
            for (BomInfoImportModel model : readModelList) {
                yesSize = yesSize + 1;
                if ("失败".equals(model.getImportSuccess())) {
                    errorSize = errorSize + 1;
                    //sb.append(model.getImportMsg()+";");
                } else {
                    successSize = successSize + 1;
                }
            }
            String returnMsg = "";
            if (errorSize>0){
                returnMsg = "本次一共处理【"+ yesSize+ "】条，不通过【"+ errorSize+"】条，"+ "通过【"+ successSize+ "条】。具体失败原因请在下载的导入结果文件中查看。";
                String originalFilename = file.getOriginalFilename();
                String downloadFilename = originalFilename.substring(0,originalFilename.indexOf("."))+"【导入结果】"+new Date().getTime();//
                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                EasyExcel.write(byteArrayOutputStream, BomInfoImportModel.class).sheet("导入结果").doWrite(readModelList);
                InputStream inputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
                MxpioFileInfo mxpioFileInfo = fileService.put("FileSystem", inputStream, downloadFilename+".xlsx",byteArrayOutputStream.size(),"");
                Result<Object> error = Result.error(returnMsg);
                error.setResult(mxpioFileInfo);
                return error;
            }else{
                returnMsg = "本次一共处理【"+ yesSize+ "】条，不通过【"+ errorSize+"】条，"+ "通过【"+ successSize+ "条】。";
                return Result.OK(returnMsg,readModelList);
            }
        } catch (Exception e) {
            return Result.error("导入失败");
        }
    }
    @GetMapping("findCircularReferenceBoms")
    @Operation(summary = "查找bom循环引用超过50层的物料bom", description = "查找bom循环引用超过50层的物料bom", method = "GET")
    public Result<List<Map<String, Object>>> findCircularReferenceBom() {
        List<Map<String, Object>> circularReferenceBom = vBomInfoService.findCircularReferenceBom();
        return Result.OK(circularReferenceBom);
    }

    @RequestMapping("exportUnBomList")
    @Operation(summary = "导出非bom物料", description = "导出非bom物料")
    public Result<?> exportUnBomList(HttpServletRequest request) {
        try{
            String downloadFilename = "非bom物料"+new Date().getTime();//
            List<BomInfoModel> readModelList =  bomInfoService.getUnBomItemList();
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            EasyExcel.write(byteArrayOutputStream, BomInfoModel.class).sheet("sheet1").doWrite(readModelList);
            InputStream inputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
            MxpioFileInfo mxpioFileInfo = fileService.put("FileSystem", inputStream, downloadFilename+".xlsx",byteArrayOutputStream.size(),"");
            Result<Object> error = Result.OK();
            error.setResult(mxpioFileInfo);
            return error;
        } catch (Exception e) {
            return Result.error("下载失败");
        }
    }

    @GetMapping("bom_stock_analysis/{productItemCode}/{referenceDate}")
    @Operation(summary = "产品bom实时库存分析", description = "产品bom实时库存分析，返回对象中，msg为最小成套数量，data为返回对象list", method = "GET")
    public Result<List<ProductBomStockAnalysisVO>> productBomStockAnalysis(@Parameter(description="产品编码") @PathVariable(name = "productItemCode", required = true) String productItemCode,
                                                                      @Parameter(description="参考日期，格式yyyy-MM-dd") @PathVariable(name = "referenceDate", required = true) String referenceDate) {
        return bomInfoService.productBomStockAnalysis(productItemCode,referenceDate);
    }

    @GetMapping("copy_target/page")
    @Operation(summary = "copyBom时，可选产品bom列表", description = "copyBom时，可选产品bom列表", method = "GET")
    public Result<Page<BomInfo>> copyTargetPage(Criteria criteria, Integer pageSize, Integer pageNo) {
        Pageable page = PageRequest.of(pageNo-1, pageSize);
        return Result.OK(bomInfoService.copyTargetPage(page,criteria));
    }

}
